Do not require iiurlwidth when getting thumbnails.
[lhc/web/wiklou.git] / includes / api / ApiQueryImageInfo.php
1 <?php
2 /**
3 *
4 *
5 * Created on July 6, 2007
6 *
7 * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * http://www.gnu.org/copyleft/gpl.html
23 *
24 * @file
25 */
26
27 /**
28 * A query action to get image information and upload history.
29 *
30 * @ingroup API
31 */
32 class ApiQueryImageInfo extends ApiQueryBase {
33 const TRANSFORM_LIMIT = 50;
34 private static $transformCount = 0;
35
36 public function __construct( ApiQuery $query, $moduleName, $prefix = 'ii' ) {
37 // We allow a subclass to override the prefix, to create a related API
38 // module. Some other parts of MediaWiki construct this with a null
39 // $prefix, which used to be ignored when this only took two arguments
40 if ( is_null( $prefix ) ) {
41 $prefix = 'ii';
42 }
43 parent::__construct( $query, $moduleName, $prefix );
44 }
45
46 public function execute() {
47 $params = $this->extractRequestParams();
48
49 $prop = array_flip( $params['prop'] );
50
51 $scale = $this->getScale( $params );
52
53 $opts = array(
54 'version' => $params['metadataversion'],
55 'language' => $params['extmetadatalanguage'],
56 'multilang' => $params['extmetadatamultilang'],
57 'extmetadatafilter' => $params['extmetadatafilter'],
58 'revdelUser' => $this->getUser(),
59 );
60
61 $pageIds = $this->getPageSet()->getAllTitlesByNamespace();
62 if ( !empty( $pageIds[NS_FILE] ) ) {
63 $titles = array_keys( $pageIds[NS_FILE] );
64 asort( $titles ); // Ensure the order is always the same
65
66 $fromTitle = null;
67 if ( !is_null( $params['continue'] ) ) {
68 $cont = explode( '|', $params['continue'] );
69 $this->dieContinueUsageIf( count( $cont ) != 2 );
70 $fromTitle = strval( $cont[0] );
71 $fromTimestamp = $cont[1];
72 // Filter out any titles before $fromTitle
73 foreach ( $titles as $key => $title ) {
74 if ( $title < $fromTitle ) {
75 unset( $titles[$key] );
76 } else {
77 break;
78 }
79 }
80 }
81
82 $user = $this->getUser();
83 $findTitles = array_map( function ( $title ) use ( $user ) {
84 return array(
85 'title' => $title,
86 'private' => $user,
87 );
88 }, $titles );
89
90 if ( $params['localonly'] ) {
91 $images = RepoGroup::singleton()->getLocalRepo()->findFiles( $findTitles );
92 } else {
93 $images = RepoGroup::singleton()->findFiles( $findTitles );
94 }
95
96 $result = $this->getResult();
97 foreach ( $titles as $title ) {
98 $pageId = $pageIds[NS_FILE][$title];
99 $start = $title === $fromTitle ? $fromTimestamp : $params['start'];
100
101 if ( !isset( $images[$title] ) ) {
102 if ( isset( $prop['uploadwarning'] ) ) {
103 // Uploadwarning needs info about non-existing files
104 $images[$title] = wfLocalFile( $title );
105 } else {
106 $result->addValue(
107 array( 'query', 'pages', intval( $pageId ) ),
108 'imagerepository', ''
109 );
110 // The above can't fail because it doesn't increase the result size
111 continue;
112 }
113 }
114
115 /** @var $img File */
116 $img = $images[$title];
117
118 if ( self::getTransformCount() >= self::TRANSFORM_LIMIT ) {
119 if ( count( $pageIds[NS_FILE] ) == 1 ) {
120 // See the 'the user is screwed' comment below
121 $this->setContinueEnumParameter( 'start',
122 $start !== null ? $start : wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
123 );
124 } else {
125 $this->setContinueEnumParameter( 'continue',
126 $this->getContinueStr( $img, $start ) );
127 }
128 break;
129 }
130
131 $fit = $result->addValue(
132 array( 'query', 'pages', intval( $pageId ) ),
133 'imagerepository', $img->getRepoName()
134 );
135 if ( !$fit ) {
136 if ( count( $pageIds[NS_FILE] ) == 1 ) {
137 // The user is screwed. imageinfo can't be solely
138 // responsible for exceeding the limit in this case,
139 // so set a query-continue that just returns the same
140 // thing again. When the violating queries have been
141 // out-continued, the result will get through
142 $this->setContinueEnumParameter( 'start',
143 $start !== null ? $start : wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
144 );
145 } else {
146 $this->setContinueEnumParameter( 'continue',
147 $this->getContinueStr( $img, $start ) );
148 }
149 break;
150 }
151
152 // Check if we can make the requested thumbnail, and get transform parameters.
153 $finalThumbParams = $this->mergeThumbParams( $img, $scale, $params['urlparam'] );
154
155 // Get information about the current version first
156 // Check that the current version is within the start-end boundaries
157 $gotOne = false;
158 if (
159 ( is_null( $start ) || $img->getTimestamp() <= $start ) &&
160 ( is_null( $params['end'] ) || $img->getTimestamp() >= $params['end'] )
161 ) {
162 $gotOne = true;
163
164 $fit = $this->addPageSubItem( $pageId,
165 self::getInfo( $img, $prop, $result,
166 $finalThumbParams, $opts
167 )
168 );
169 if ( !$fit ) {
170 if ( count( $pageIds[NS_FILE] ) == 1 ) {
171 // See the 'the user is screwed' comment above
172 $this->setContinueEnumParameter( 'start',
173 wfTimestamp( TS_ISO_8601, $img->getTimestamp() ) );
174 } else {
175 $this->setContinueEnumParameter( 'continue',
176 $this->getContinueStr( $img ) );
177 }
178 break;
179 }
180 }
181
182 // Now get the old revisions
183 // Get one more to facilitate query-continue functionality
184 $count = ( $gotOne ? 1 : 0 );
185 $oldies = $img->getHistory( $params['limit'] - $count + 1, $start, $params['end'] );
186 /** @var $oldie File */
187 foreach ( $oldies as $oldie ) {
188 if ( ++$count > $params['limit'] ) {
189 // We've reached the extra one which shows that there are
190 // additional pages to be had. Stop here...
191 // Only set a query-continue if there was only one title
192 if ( count( $pageIds[NS_FILE] ) == 1 ) {
193 $this->setContinueEnumParameter( 'start',
194 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
195 }
196 break;
197 }
198 $fit = self::getTransformCount() < self::TRANSFORM_LIMIT &&
199 $this->addPageSubItem( $pageId,
200 self::getInfo( $oldie, $prop, $result,
201 $finalThumbParams, $opts
202 )
203 );
204 if ( !$fit ) {
205 if ( count( $pageIds[NS_FILE] ) == 1 ) {
206 $this->setContinueEnumParameter( 'start',
207 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
208 } else {
209 $this->setContinueEnumParameter( 'continue',
210 $this->getContinueStr( $oldie ) );
211 }
212 break;
213 }
214 }
215 if ( !$fit ) {
216 break;
217 }
218 }
219 }
220 }
221
222 /**
223 * From parameters, construct a 'scale' array
224 * @param array $params Parameters passed to api.
225 * @return array|null Key-val array of 'width' and 'height', or null
226 */
227 public function getScale( $params ) {
228 $p = $this->getModulePrefix();
229
230 if ( $params['urlwidth'] != -1 ) {
231 $scale = array();
232 $scale['width'] = $params['urlwidth'];
233 $scale['height'] = $params['urlheight'];
234 } elseif ( $params['urlheight'] != -1 ) {
235 // Height is specified but width isn't
236 // Don't set $scale['width']; this signals mergeThumbParams() to fill it with the image's width
237 $scale = array();
238 $scale['height'] = $params['urlheight'];
239 } else {
240 if ( $params['urlparam'] ) {
241 // Audio files might not have a width/height.
242 $scale = array();
243 } else {
244 $scale = null;
245 }
246 }
247
248 return $scale;
249 }
250
251 /** Validate and merge scale parameters with handler thumb parameters, give error if invalid.
252 *
253 * We do this later than getScale, since we need the image
254 * to know which handler, since handlers can make their own parameters.
255 * @param File $image Image that params are for.
256 * @param array $thumbParams Thumbnail parameters from getScale
257 * @param string $otherParams String of otherParams (iiurlparam).
258 * @return array Array of parameters for transform.
259 */
260 protected function mergeThumbParams( $image, $thumbParams, $otherParams ) {
261 if ( $thumbParams === null ) {
262 // No scaling requested
263 return null;
264 }
265 if ( !isset( $thumbParams['width'] ) && isset( $thumbParams['height'] ) ) {
266 // We want to limit only by height in this situation, so pass the
267 // image's full width as the limiting width. But some file types
268 // don't have a width of their own, so pick something arbitrary so
269 // thumbnailing the default icon works.
270 if ( $image->getWidth() <= 0 ) {
271 $thumbParams['width'] = max( $this->getConfig()->get( 'ThumbLimits' ) );
272 } else {
273 $thumbParams['width'] = $image->getWidth();
274 }
275 }
276
277 if ( !$otherParams ) {
278 $this->checkParameterNormalise( $image, $thumbParams );
279 return $thumbParams;
280 }
281 $p = $this->getModulePrefix();
282
283 $h = $image->getHandler();
284 if ( !$h ) {
285 $this->setWarning( 'Could not create thumbnail because ' .
286 $image->getName() . ' does not have an associated image handler' );
287
288 return $thumbParams;
289 }
290
291 $paramList = $h->parseParamString( $otherParams );
292 if ( !$paramList ) {
293 // Just set a warning (instead of dieUsage), as in many cases
294 // we could still render the image using width and height parameters,
295 // and this type of thing could happen between different versions of
296 // handlers.
297 $this->setWarning( "Could not parse {$p}urlparam for " . $image->getName()
298 . '. Using only width and height' );
299 $this->checkParameterNormalise( $image, $thumbParams );
300 return $thumbParams;
301 }
302
303 if ( isset( $paramList['width'] ) && isset( $thumbParams['width'] ) ) {
304 if ( intval( $paramList['width'] ) != intval( $thumbParams['width'] ) ) {
305 $this->setWarning( "Ignoring width value set in {$p}urlparam ({$paramList['width']}) "
306 . "in favor of width value derived from {$p}urlwidth/{$p}urlheight "
307 . "({$thumbParams['width']})" );
308 }
309 }
310
311 foreach ( $paramList as $name => $value ) {
312 if ( !$h->validateParam( $name, $value ) ) {
313 $this->dieUsage( "Invalid value for {$p}urlparam ($name=$value)", "urlparam" );
314 }
315 }
316
317 $finalParams = $thumbParams + $paramList;
318 $this->checkParameterNormalise( $image, $finalParams );
319 return $finalParams;
320 }
321
322 /**
323 * Verify that the final image parameters can be normalised.
324 *
325 * This doesn't use the normalised parameters, since $file->transform
326 * expects the pre-normalised parameters, but doing the normalisation
327 * allows us to catch certain error conditions early (such as missing
328 * required parameter).
329 *
330 * @param $image File
331 * @param $finalParams array List of parameters to transform image with
332 */
333 protected function checkParameterNormalise( $image, $finalParams ) {
334 $h = $image->getHandler();
335 if ( !$h ) {
336 return;
337 }
338 // Note: normaliseParams modifies the array in place, but we aren't interested
339 // in the actual normalised version, only if we can actually normalise them,
340 // so we use the functions scope to throw away the normalisations.
341 if ( !$h->normaliseParams( $image, $finalParams ) ) {
342 $this->dieUsage( "Could not normalise image parameters for " . $image->getName(), "urlparamnormal" );
343 }
344 }
345
346 /**
347 * Get result information for an image revision
348 *
349 * @param File $file
350 * @param array $prop Array of properties to get (in the keys)
351 * @param ApiResult $result
352 * @param array $thumbParams Containing 'width' and 'height' items, or null
353 * @param array|bool|string $opts Options for data fetching.
354 * This is an array consisting of the keys:
355 * 'version': The metadata version for the metadata option
356 * 'language': The language for extmetadata property
357 * 'multilang': Return all translations in extmetadata property
358 * 'revdelUser': User to use when checking whether to show revision-deleted fields.
359 * @return array Result array
360 */
361 static function getInfo( $file, $prop, $result, $thumbParams = null, $opts = false ) {
362 global $wgContLang;
363
364 $anyHidden = false;
365
366 if ( !$opts || is_string( $opts ) ) {
367 $opts = array(
368 'version' => $opts ?: 'latest',
369 'language' => $wgContLang,
370 'multilang' => false,
371 'extmetadatafilter' => array(),
372 'revdelUser' => null,
373 );
374 }
375 $version = $opts['version'];
376 $vals = array();
377 // Timestamp is shown even if the file is revdelete'd in interface
378 // so do same here.
379 if ( isset( $prop['timestamp'] ) ) {
380 $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $file->getTimestamp() );
381 }
382
383 // Handle external callers who don't pass revdelUser
384 if ( isset( $opts['revdelUser'] ) && $opts['revdelUser'] ) {
385 $revdelUser = $opts['revdelUser'];
386 $canShowField = function ( $field ) use ( $file, $revdelUser ) {
387 return $file->userCan( $field, $revdelUser );
388 };
389 } else {
390 $canShowField = function ( $field ) use ( $file ) {
391 return !$file->isDeleted( $field );
392 };
393 }
394
395 $user = isset( $prop['user'] );
396 $userid = isset( $prop['userid'] );
397
398 if ( $user || $userid ) {
399 if ( $file->isDeleted( File::DELETED_USER ) ) {
400 $vals['userhidden'] = '';
401 $anyHidden = true;
402 }
403 if ( $canShowField( File::DELETED_USER ) ) {
404 if ( $user ) {
405 $vals['user'] = $file->getUser();
406 }
407 if ( $userid ) {
408 $vals['userid'] = $file->getUser( 'id' );
409 }
410 if ( !$file->getUser( 'id' ) ) {
411 $vals['anon'] = '';
412 }
413 }
414 }
415
416 // This is shown even if the file is revdelete'd in interface
417 // so do same here.
418 if ( isset( $prop['size'] ) || isset( $prop['dimensions'] ) ) {
419 $vals['size'] = intval( $file->getSize() );
420 $vals['width'] = intval( $file->getWidth() );
421 $vals['height'] = intval( $file->getHeight() );
422
423 $pageCount = $file->pageCount();
424 if ( $pageCount !== false ) {
425 $vals['pagecount'] = $pageCount;
426 }
427 }
428
429 $pcomment = isset( $prop['parsedcomment'] );
430 $comment = isset( $prop['comment'] );
431
432 if ( $pcomment || $comment ) {
433 if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
434 $vals['commenthidden'] = '';
435 $anyHidden = true;
436 }
437 if ( $canShowField( File::DELETED_COMMENT ) ) {
438 if ( $pcomment ) {
439 $vals['parsedcomment'] = Linker::formatComment(
440 $file->getDescription( File::RAW ), $file->getTitle() );
441 }
442 if ( $comment ) {
443 $vals['comment'] = $file->getDescription( File::RAW );
444 }
445 }
446 }
447
448 $canonicaltitle = isset( $prop['canonicaltitle'] );
449 $url = isset( $prop['url'] );
450 $sha1 = isset( $prop['sha1'] );
451 $meta = isset( $prop['metadata'] );
452 $extmetadata = isset( $prop['extmetadata'] );
453 $commonmeta = isset( $prop['commonmetadata'] );
454 $mime = isset( $prop['mime'] );
455 $mediatype = isset( $prop['mediatype'] );
456 $archive = isset( $prop['archivename'] );
457 $bitdepth = isset( $prop['bitdepth'] );
458 $uploadwarning = isset( $prop['uploadwarning'] );
459
460 if ( $uploadwarning ) {
461 $vals['html'] = SpecialUpload::getExistsWarning( UploadBase::getExistsWarning( $file ) );
462 }
463
464 if ( $file->isDeleted( File::DELETED_FILE ) ) {
465 $vals['filehidden'] = '';
466 $anyHidden = true;
467 }
468
469 if ( $anyHidden && $file->isDeleted( File::DELETED_RESTRICTED ) ) {
470 $vals['suppressed'] = true;
471 }
472
473 if ( !$canShowField( File::DELETED_FILE ) ) {
474 //Early return, tidier than indenting all following things one level
475 return $vals;
476 }
477
478 if ( $canonicaltitle ) {
479 $vals['canonicaltitle'] = $file->getTitle()->getPrefixedText();
480 }
481
482 if ( $url ) {
483 if ( !is_null( $thumbParams ) ) {
484 $mto = $file->transform( $thumbParams );
485 self::$transformCount++;
486 if ( $mto && !$mto->isError() ) {
487 $vals['thumburl'] = wfExpandUrl( $mto->getUrl(), PROTO_CURRENT );
488
489 // bug 23834 - If the URL's are the same, we haven't resized it, so shouldn't give the wanted
490 // thumbnail sizes for the thumbnail actual size
491 if ( $mto->getUrl() !== $file->getUrl() ) {
492 $vals['thumbwidth'] = intval( $mto->getWidth() );
493 $vals['thumbheight'] = intval( $mto->getHeight() );
494 } else {
495 $vals['thumbwidth'] = intval( $file->getWidth() );
496 $vals['thumbheight'] = intval( $file->getHeight() );
497 }
498
499 if ( isset( $prop['thumbmime'] ) && $file->getHandler() ) {
500 list( , $mime ) = $file->getHandler()->getThumbType(
501 $mto->getExtension(), $file->getMimeType(), $thumbParams );
502 $vals['thumbmime'] = $mime;
503 }
504 } elseif ( $mto && $mto->isError() ) {
505 $vals['thumberror'] = $mto->toText();
506 }
507 }
508 $vals['url'] = wfExpandUrl( $file->getFullURL(), PROTO_CURRENT );
509 $vals['descriptionurl'] = wfExpandUrl( $file->getDescriptionUrl(), PROTO_CURRENT );
510 }
511
512 if ( $sha1 ) {
513 $vals['sha1'] = wfBaseConvert( $file->getSha1(), 36, 16, 40 );
514 }
515
516 if ( $meta ) {
517 wfSuppressWarnings();
518 $metadata = unserialize( $file->getMetadata() );
519 wfRestoreWarnings();
520 if ( $metadata && $version !== 'latest' ) {
521 $metadata = $file->convertMetadataVersion( $metadata, $version );
522 }
523 $vals['metadata'] = $metadata ? self::processMetaData( $metadata, $result ) : null;
524 }
525 if ( $commonmeta ) {
526 $metaArray = $file->getCommonMetaArray();
527 $vals['commonmetadata'] = $metaArray ? self::processMetaData( $metaArray, $result ) : array();
528 }
529
530 if ( $extmetadata ) {
531 // Note, this should return an array where all the keys
532 // start with a letter, and all the values are strings.
533 // Thus there should be no issue with format=xml.
534 $format = new FormatMetadata;
535 $format->setSingleLanguage( !$opts['multilang'] );
536 $format->getContext()->setLanguage( $opts['language'] );
537 $extmetaArray = $format->fetchExtendedMetadata( $file );
538 if ( $opts['extmetadatafilter'] ) {
539 $extmetaArray = array_intersect_key(
540 $extmetaArray, array_flip( $opts['extmetadatafilter'] )
541 );
542 }
543 $vals['extmetadata'] = $extmetaArray;
544 }
545
546 if ( $mime ) {
547 $vals['mime'] = $file->getMimeType();
548 }
549
550 if ( $mediatype ) {
551 $vals['mediatype'] = $file->getMediaType();
552 }
553
554 if ( $archive && $file->isOld() ) {
555 $vals['archivename'] = $file->getArchiveName();
556 }
557
558 if ( $bitdepth ) {
559 $vals['bitdepth'] = $file->getBitDepth();
560 }
561
562 return $vals;
563 }
564
565 /**
566 * Get the count of image transformations performed
567 *
568 * If this is >= TRANSFORM_LIMIT, you should probably stop processing images.
569 *
570 * @return int Count
571 */
572 static function getTransformCount() {
573 return self::$transformCount;
574 }
575
576 /**
577 *
578 * @param array $metadata
579 * @param ApiResult $result
580 * @return array
581 */
582 public static function processMetaData( $metadata, $result ) {
583 $retval = array();
584 if ( is_array( $metadata ) ) {
585 foreach ( $metadata as $key => $value ) {
586 $r = array( 'name' => $key );
587 if ( is_array( $value ) ) {
588 $r['value'] = self::processMetaData( $value, $result );
589 } else {
590 $r['value'] = $value;
591 }
592 $retval[] = $r;
593 }
594 }
595 $result->setIndexedTagName( $retval, 'metadata' );
596
597 return $retval;
598 }
599
600 public function getCacheMode( $params ) {
601 if ( $this->userCanSeeRevDel() ) {
602 return 'private';
603 }
604
605 return 'public';
606 }
607
608 /**
609 * @param File $img
610 * @param null|string $start
611 * @return string
612 */
613 protected function getContinueStr( $img, $start = null ) {
614 if ( $start === null ) {
615 $start = $img->getTimestamp();
616 }
617
618 return $img->getOriginalTitle()->getDBkey() . '|' . $start;
619 }
620
621 public function getAllowedParams() {
622 global $wgContLang;
623
624 return array(
625 'prop' => array(
626 ApiBase::PARAM_ISMULTI => true,
627 ApiBase::PARAM_DFLT => 'timestamp|user',
628 ApiBase::PARAM_TYPE => self::getPropertyNames()
629 ),
630 'limit' => array(
631 ApiBase::PARAM_TYPE => 'limit',
632 ApiBase::PARAM_DFLT => 1,
633 ApiBase::PARAM_MIN => 1,
634 ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
635 ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
636 ),
637 'start' => array(
638 ApiBase::PARAM_TYPE => 'timestamp'
639 ),
640 'end' => array(
641 ApiBase::PARAM_TYPE => 'timestamp'
642 ),
643 'urlwidth' => array(
644 ApiBase::PARAM_TYPE => 'integer',
645 ApiBase::PARAM_DFLT => -1
646 ),
647 'urlheight' => array(
648 ApiBase::PARAM_TYPE => 'integer',
649 ApiBase::PARAM_DFLT => -1
650 ),
651 'metadataversion' => array(
652 ApiBase::PARAM_TYPE => 'string',
653 ApiBase::PARAM_DFLT => '1',
654 ),
655 'extmetadatalanguage' => array(
656 ApiBase::PARAM_TYPE => 'string',
657 ApiBase::PARAM_DFLT => $wgContLang->getCode(),
658 ),
659 'extmetadatamultilang' => array(
660 ApiBase::PARAM_TYPE => 'boolean',
661 ApiBase::PARAM_DFLT => false,
662 ),
663 'extmetadatafilter' => array(
664 ApiBase::PARAM_TYPE => 'string',
665 ApiBase::PARAM_ISMULTI => true,
666 ),
667 'urlparam' => array(
668 ApiBase::PARAM_DFLT => '',
669 ApiBase::PARAM_TYPE => 'string',
670 ),
671 'continue' => null,
672 'localonly' => false,
673 );
674 }
675
676 /**
677 * Returns all possible parameters to iiprop
678 *
679 * @param array $filter List of properties to filter out
680 *
681 * @return array
682 */
683 public static function getPropertyNames( $filter = array() ) {
684 return array_diff( array_keys( self::getProperties() ), $filter );
685 }
686
687 /**
688 * Returns array key value pairs of properties and their descriptions
689 *
690 * @param string $modulePrefix
691 * @return array
692 */
693 private static function getProperties( $modulePrefix = '' ) {
694 return array(
695 'timestamp' => ' timestamp - Adds timestamp for the uploaded version',
696 'user' => ' user - Adds the user who uploaded the image version',
697 'userid' => ' userid - Add the user ID that uploaded the image version',
698 'comment' => ' comment - Comment on the version',
699 'parsedcomment' => ' parsedcomment - Parse the comment on the version',
700 'canonicaltitle' => ' canonicaltitle - Adds the canonical title of the image file',
701 'url' => ' url - Gives URL to the image and the description page',
702 'size' => ' size - Adds the size of the image in bytes ' .
703 'and the height, width and page count (if applicable)',
704 'dimensions' => ' dimensions - Alias for size', // B/C with Allimages
705 'sha1' => ' sha1 - Adds SHA-1 hash for the image',
706 'mime' => ' mime - Adds MIME type of the image',
707 'thumbmime' => ' thumbmime - Adds MIME type of the image thumbnail' .
708 ' (requires url and param ' . $modulePrefix . 'urlwidth)',
709 'mediatype' => ' mediatype - Adds the media type of the image',
710 'metadata' => ' metadata - Lists Exif metadata for the version of the image',
711 'commonmetadata' => ' commonmetadata - Lists file format generic metadata ' .
712 'for the version of the image',
713 'extmetadata' => ' extmetadata - Lists formatted metadata combined ' .
714 'from multiple sources. Results are HTML formatted.',
715 'archivename' => ' archivename - Adds the file name of the archive ' .
716 'version for non-latest versions',
717 'bitdepth' => ' bitdepth - Adds the bit depth of the version',
718 'uploadwarning' => ' uploadwarning - Used by the Special:Upload page to ' .
719 'get information about an existing file. Not intended for use outside MediaWiki core',
720 );
721 }
722
723 /**
724 * Returns the descriptions for the properties provided by getPropertyNames()
725 *
726 * @param array $filter List of properties to filter out
727 * @param string $modulePrefix
728 * @return array
729 */
730 public static function getPropertyDescriptions( $filter = array(), $modulePrefix = '' ) {
731 return array_merge(
732 array( 'What image information to get:' ),
733 array_values( array_diff_key( self::getProperties( $modulePrefix ), array_flip( $filter ) ) )
734 );
735 }
736
737 /**
738 * Return the API documentation for the parameters.
739 * @return array Parameter documentation.
740 */
741 public function getParamDescription() {
742 $p = $this->getModulePrefix();
743
744 return array(
745 'prop' => self::getPropertyDescriptions( array(), $p ),
746 'urlwidth' => array(
747 "If {$p}prop=url is set, a URL to an image scaled to this width will be returned.",
748 'For performance reasons if this option is used, ' .
749 'no more than ' . self::TRANSFORM_LIMIT . ' scaled images will be returned.'
750 ),
751 'urlheight' => "Similar to {$p}urlwidth.",
752 'urlparam' => array(
753 "A handler specific parameter string. For example, pdf's ",
754 "might use 'page15-100px'."
755 ),
756 'limit' => 'How many image revisions to return per image',
757 'start' => 'Timestamp to start listing from',
758 'end' => 'Timestamp to stop listing at',
759 'metadataversion'
760 => array( "Version of metadata to use. if 'latest' is specified, use latest version.",
761 "Defaults to '1' for backwards compatibility" ),
762 'extmetadatalanguage' => array(
763 'What language to fetch extmetadata in. This affects both which',
764 'translation to fetch, if multiple are available, as well as how things',
765 'like numbers and various values are formatted.'
766 ),
767 'extmetadatamultilang'
768 =>'If translations for extmetadata property are available, fetch all of them.',
769 'extmetadatafilter'
770 => "If specified and non-empty, only these keys will be returned for {$p}prop=extmetadata",
771 'continue' => 'If the query response includes a continue value, ' .
772 'use it here to get another page of results',
773 'localonly' => 'Look only for files in the local repository',
774 );
775 }
776
777 public function getDescription() {
778 return 'Returns image information and upload history.';
779 }
780
781 public function getExamples() {
782 return array(
783 'api.php?action=query&titles=File:Albert%20Einstein%20Head.jpg&prop=imageinfo',
784 'api.php?action=query&titles=File:Test.jpg&prop=imageinfo&iilimit=50&' .
785 'iiend=20071231235959&iiprop=timestamp|user|url',
786 );
787 }
788
789 public function getHelpUrls() {
790 return 'https://www.mediawiki.org/wiki/API:Properties#imageinfo_.2F_ii';
791 }
792 }